use axum::body::Body;
use axum::extract::Request;
use axum::{
    Router,
    extract::OriginalUri,
    http::StatusCode,
    response::IntoResponse,
    routing::{any, get},
};

use utoipa_axum::router::OpenApiRouter;
use utoipa_swagger_ui::SwaggerUi;

pub mod resp;

use crate::{bootstrap::AppState, controller};

use utoipa::{
    Modify, OpenApi,
    openapi::security::{ApiKey, ApiKeyValue, SecurityScheme},
};

#[derive(OpenApi)]
#[openapi(
    // modifiers(&SecurityAddon),
    paths(controller::hello_world)
)]
struct ApiDoc;

pub async fn create_routes() -> Router<AppState> {
    let (router, api) = OpenApiRouter::with_openapi(ApiDoc::openapi())
        .route("/", get(controller::hello_world))
        .route("/{name}", get(controller::hello_world))
        .split_for_parts();

    let router = router
        .merge(SwaggerUi::new("/swagger-ui").url("/api-docs/openapi.json", api.clone()))
        .fallback(any(handler_404));

    router
}

#[axum::debug_handler]
async fn handler_404(uri: OriginalUri, resp: Request<Body>) -> impl IntoResponse {
    let error_url = uri.to_string();
    tracing::error!(" handler_404 : {} ", error_url);

    resp::RespVO::<()> {
        code: StatusCode::NOT_FOUND.as_u16(),
        msg: Some(format!(
            "URL {} The requested resource was not found, method: {}",
            error_url.as_str(),
            resp.method()
        )),
        data: None,
    }
    .to_string()
}
